﻿using System;
using System.Reflection;

namespace CRM.Extensions
{
    public static class ObjExtensions
    {
        /// <summary>
        /// 获取对象的字段或属性值 
        /// </summary>
        /// Implement From <see cref="Coravel.Mailer.Mail.Helpers.ReflectionHelpers.GetPropOrFieldValue"/>
        /// <param name="me"></param>
        /// <param name="memberName"></param>
        /// <returns></returns>
        private static object GetPropOrFieldValue1(this object me, string memberName)
        {
            Type type = me.GetType();
            MemberInfo memberInfo = (MemberInfo) type.GetProperty(memberName);
            if ((object) memberInfo == null)
                memberInfo = (MemberInfo) type.GetField(memberName);
            switch (memberInfo)
            {
                case PropertyInfo propertyInfo:
                    return propertyInfo.GetValue(me);
                case FieldInfo fieldInfo:
                    return fieldInfo.GetValue(me);
                default:
                    return (object) null;
            }
        }

        //GetMember 比 GetProperty & GetField 效率低3倍
        private static object GetPropOrFieldValue2(this object me, string memberName)
        {
            MemberInfo memberInfo = me.GetType().GetMember(memberName,
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)[0];
            switch (memberInfo.MemberType)
            {
                case MemberTypes.Property:
                    return ((PropertyInfo) memberInfo).GetValue(me);
                case MemberTypes.Field:
                    return ((FieldInfo) memberInfo).GetValue(me);
                default:
                    return (object) null;
            }
        }

        //NET5 没有像 Framework 一样的属性字段的包装方法
        private static object GetPropOrFieldValue3(this object me, string memberName)
        {
            var memberInfo = me.GetType().GetMethod($"Get_{memberName}", BindingFlags.Instance);
            return memberInfo?.Invoke(me, null);
        }

        public static object GetPropOrFieldValue(this object me, string memberName) =>
            me.GetPropOrFieldValue1(memberName);

        public static T GetPropOrFieldValue<T>(this object me, string memberName) =>
            (T) me.GetPropOrFieldValue(memberName);

        public static void SetPropOrFieldValue(this object me, string memberName, object value)
        {
            Type type = me.GetType();
            MemberInfo memberInfo = (MemberInfo) type.GetProperty(memberName);
            if ((object) memberInfo == null)
                memberInfo = (MemberInfo) type.GetField(memberName);
            switch (memberInfo)
            {
                case PropertyInfo propertyInfo:
                    propertyInfo.SetValue(me, value);
                    break;
                case FieldInfo fieldInfo:
                    fieldInfo.SetValue(me, value);
                    break;
            }
        }

        public static bool IsNull(this object me)
        {
            return null == me;
        }
        public static bool IsNotNull(this object me)
        {
            return null != me;
        }
    }
}